// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UIPortfolio.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.Forge.UI.Forms
{
    #region Using Directives

    using System;
    using System.ComponentModel;

    using Org.OpenTrader.Framework.Events;
    using Org.OpenTrader.Framework.Forge.Enums;
    using Org.OpenTrader.Framework.Forge.Events;
    using Org.OpenTrader.Framework.Forge.Interfaces;
    using Org.OpenTrader.Framework.LinqKit;
    using Org.OpenTrader.Framework.UI.Forms;

    #endregion

    /// <summary>
    /// The ui security service.
    /// </summary>
    public partial class UIPortfolio : UIControl
    {
        #region Constants and Fields

        /// <summary>
        /// Check if the potfolio is built or not
        /// </summary>
        private bool built;

        /// <summary>
        /// The current executions.
        /// </summary>
        private IExecution[] currentExecutions;

        /// <summary>
        /// The current tracking cells.
        /// </summary>
        private IOrderTrackingCell[] currentTrackingCells;

        /// <summary>
        /// The instruments.
        /// </summary>
        private IInstrument[] instruments;

        /// <summary>
        /// The expotype.
        /// </summary>
        private EExpoCellType selectedExpoType;

        /// <summary>
        /// The selected instrument.
        /// </summary>
        private IInstrument selectedInstrument;

        /// <summary>
        /// The Selected Instrument View
        /// </summary>
        private InstrumentView selectedInstrumentView;

        /// <summary>
        /// The Trading scope.
        /// </summary>
        private ETradingScope selectedTradingScope;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UIPortfolio"/> class.
        /// </summary>
        public UIPortfolio()
        {
            this.InitializeComponent();

            // ExpoEnum
            var enumValues = Enum.GetValues(typeof(EExpoCellType));
            foreach (var enumValue in enumValues)
            {
                this.ExpositionTypeCombobox.Items.Add(enumValue);
            }

            this.ExpositionTypeCombobox.SelectedIndex = 0;

            // TradingScopeEnum
            var trsenumValues = Enum.GetValues(typeof(ETradingScope));
            foreach (var enumValue in trsenumValues)
            {
                this.TradingScopeCombobox.Items.Add(enumValue);
            }

            this.TradingScopeCombobox.SelectedIndex = 0;
            this.built = true;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets Executions.
        /// </summary>
        public IExecution[] Executions
        {
            get
            {
                return this.currentExecutions;
            }

            private set
            {
                this.uiExecutionsVirtualGrid.Rows.Clear();
                this.currentExecutions = value;
            }
        }

        /// <summary>
        /// Gets Instrument.
        /// </summary>
        public IInstrument Instrument
        {
            get
            {
                return this.selectedInstrument;
            }

            private set
            {
                if (this.selectedInstrument != null)
                {
                    this.selectedInstrument.OrderTrackingEventCB -= this.OnOrderTracking;
                    this.currentTrackingCells = null;
                    this.currentExecutions = null;
                }

                this.uiOrderTrackingCellsVirtualGrid.Rows.Clear();
                this.uiExecutionsVirtualGrid.Rows.Clear();

                this.selectedInstrument = value;

                if (this.selectedInstrument != null)
                {
                    var predicateOrders = PredicateBuilder.True<IOrderTrackingCell>();
                    this.currentTrackingCells = this.selectedInstrument.OrderTracker.GetTrackingCells(predicateOrders);

                    this.selectedInstrument.OrderTrackingEventCB += this.OnOrderTracking;
                    this.Refresh();
                }
            }
        }

        /// <summary>
        /// Gets InstrumentView.
        /// </summary>
        public IInstrumentView InstrumentView
        {
            get
            {
                return this.selectedInstrumentView;
            }

            private set
            {
                this.Instrument = null;
                this.selectedInstrumentView = (InstrumentView)value;
                var predicate = PredicateBuilder.True<IInstrument>();
                predicate = predicate.And(cell => cell.InstrumentStaticData.TradingScope == this.selectedTradingScope);
                this.instruments = this.InstrumentView.GetInstruments(predicate).NestedObject;

                if (this.instruments != null)
                {
                    if (this.instruments.Length > 0)
                    {
                        this.Instrument = this.instruments[0];
                    }
                }
            }
        }

        /// <summary>
        /// Gets UniverseExpoCell.
        /// </summary>
        public IUniverseExpoCell UniverseExpoCell { get; private set; }

        /// <summary>
        /// Gets UIVirtualGrid.
        /// </summary>
        [Browsable(false)]
        public UIVirtualGrid UniverseVirtualGrid
        {
            get
            {
                return this.uiUniverseVirtualGrid;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Round price
        /// </summary>
        /// <param name="price">
        /// </param>
        /// <returns>
        /// The round.
        /// </returns>
        private static string Round(double price)
        {
            return ForgePrettyPrinter.Prices.Format(price, 0.01 / 10);
        }

        /// <summary>
        /// The executions virtual grid_ ui grid query cell info.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void ExecutionsVirtualGrid_UIGridQueryCellInfo(object sender, VirtualGridEventArgs.QueryCellInfo e)
        {
            if (e.RowIndex < 0)
            {
                return;
            }

            if (this.Executions == null)
            {
                return;
            }

            var cell = this.Executions[e.RowIndex];
            if (cell == null)
            {
                return;
            }

            // According the column display required data
            switch (e.ColumnIndex)
            {
                case 0: // Time
                    e.Value = cell.TimeStamp;
                    break;
                case 1: // Qty
                    e.Value = cell.Quantity;
                    break;
                case 2: // Price
                    e.Value = cell.Price;
                    break;
            }
        }

        /// <summary>
        /// The executions virtual grid_ ui grid query row count.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void ExecutionsVirtualGrid_UIGridQueryRowCount(object sender, VirtualGridEventArgs.QueryRowCount e)
        {
            e.RowCount = this.currentExecutions == null ? 0 : this.currentExecutions.Length;
        }

        /// <summary>
        /// The exposition type combobox_ selected index changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void ExpositionTypeComboboxSelectedIndexChanged(object sender, EventArgs e)
        {
            this.selectedExpoType = (EExpoCellType)this.ExpositionTypeCombobox.SelectedItem;
            this.ResetUniverseExpoCell();
        }

        /// <summary>
        /// The instrument view virtual grid row enter.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void InstrumentViewVirtualGridRowEnter(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
        {
            this.Instrument = this.instruments != null ? this.instruments[e.RowIndex] : null;
        }

        /// <summary>
        /// The on instrument view query cell info.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnInstrumentViewQueryCellInfo(object sender, VirtualGridEventArgs.QueryCellInfo e)
        {
            if (this.instruments == null)
            {
                return;
            }

            var i = this.instruments[e.RowIndex];
            if (i == null)
            {
                return;
            }

            // According the column display required data
            if (e.ColumnIndex == 0)
            {
                e.Value = i.ToString();
                e.ToolTip = string.Empty;
                return;
            }

            // Currency
            if (e.ColumnIndex == 1)
            {
                e.Value = i.InstrumentStaticData != null ? i.InstrumentStaticData.Currency.ToString() : "-";
                return;
            }

            // Expo columns
            var expo = i.Expo[this.selectedExpoType];
            if (expo == null)
            {
                return;
            }

            // According the column display required data
            switch (e.ColumnIndex)
            {
                case 2: // Buy average
                    e.Value = Round(expo.BuyAverageExecutedPrice);
                    e.ToolTip = string.Empty + expo.BuyAverageExecutedPrice;
                    break;

                case 3: // Buy qty
                    e.Value = expo.BuyExecutedQty;
                    break;

                case 4: // Sell average
                    e.Value = Round(expo.SellAverageExecutedPrice);
                    e.ToolTip = string.Empty + expo.SellAverageExecutedPrice;
                    break;

                case 5: // Sell qty 
                    e.Value = expo.SellExecutedQty;
                    break;

                case 6: // Inventory 
                    e.Value = expo.Inventory;
                    break;

                case 7: // Average Price
                    e.Value = Round(expo.AveragePrice);
                    e.ToolTip = string.Empty + expo.AveragePrice;
                    break;

                case 8: // Nominal
                    e.Value = Round(expo.NominalExpo);
                    e.ToolTip = string.Empty + expo.NominalExpo;
                    break;

                case 9: // Realized
                    e.Value = Round(expo.Realized);
                    e.ToolTip = string.Empty + expo.Realized;
                    break;

                case 10: // Unrealized
                    e.Value = Round(expo.UnRealized);
                    e.ToolTip = string.Empty + expo.UnRealized;
                    break;

                case 11: // Fees
                    e.Value = Round(expo.FeesTracker.Fees);
                    e.ToolTip = string.Empty + expo.FeesTracker.Fees;
                    break;

                case 12: // PNL
                    e.Value = Round(expo.PL);
                    e.ToolTip = string.Empty + expo.PL;
                    break;

                case 13: // Net PNL
                    e.Value = Round(expo.NetPL);
                    e.ToolTip = string.Empty + expo.NetPL;
                    break;
            }
        }

        /// <summary>
        /// The on instrument view query row count.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnInstrumentViewQueryRowCount(object sender, VirtualGridEventArgs.QueryRowCount e)
        {
            e.RowCount = this.instruments == null ? 0 : this.instruments.Length;
        }

        /// <summary>
        /// The on order tracking.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        private void OnOrderTracking(object sender, OrderTrackingEventArgs args)
        {
            if (this.Instrument == null)
            {
                this.currentTrackingCells = null;
                this.uiOrderTrackingCellsVirtualGrid.Rows.Clear();
            }
            else
            {
                var predicateOrders = PredicateBuilder.True<IOrderTrackingCell>();
                this.currentTrackingCells = this.Instrument.OrderTracker.GetTrackingCells(predicateOrders);
            }
        }

        /// <summary>
        /// The virtualGrid_ ui grid query cell info.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnUniverseVirtualGridQueryCellInfo(object sender, VirtualGridEventArgs.QueryCellInfo e)
        {
            var codes = Singleton<Universe>.Instance.InstrumentViews;
            if (codes == null)
            {
                return;
            }

            var code = codes[e.RowIndex];
            var i = (InstrumentView)Singleton<Universe>.Instance[code];
            if (i == null)
            {
                return;
            }

            // According the column display required data
            if (e.ColumnIndex == 0)
            {
                e.Value = i.ToString();
                e.ToolTip = string.Empty;
                return;
            }

            // Nb Instrument
            if (e.ColumnIndex == 1)
            {
                e.Value = i.Nb;
                return;
            }

            // Expo columns
            var expolist = i[this.selectedTradingScope];
            if (expolist == null)
            {
                e.Value = "-";
                return;
            }

            var expo = expolist[this.selectedExpoType];

            // According the column display required data
            switch (e.ColumnIndex)
            {
                case 2: // Currency
                    e.Value = i.Currency;
                    break;

                case 3: // Buy average
                    e.Value = Round(expo.BuyAverageExecutedPrice);
                    e.ToolTip = string.Empty + expo.BuyAverageExecutedPrice;
                    break;

                case 4: // Buy qty
                    e.Value = expo.BuyExecutedQty;
                    break;

                case 5: // Sell average
                    e.Value = Round(expo.SellAverageExecutedPrice);
                    e.ToolTip = string.Empty + expo.SellAverageExecutedPrice;
                    break;

                case 6: // Sell qty 
                    e.Value = expo.SellExecutedQty;
                    break;

                case 7: // Inventory 
                    e.Value = expo.Inventory;
                    break;

                case 8: // Average Price
                    e.Value = Round(expo.AveragePrice);
                    e.ToolTip = string.Empty + expo.AveragePrice;
                    break;

                case 9: // Nominal
                    e.Value = Round(expo.NominalExpo);
                    e.ToolTip = string.Empty + expo.NominalExpo;
                    break;

                case 10: // Realized
                    e.Value = Round(expo.Realized);
                    e.ToolTip = string.Empty + expo.Realized;
                    break;

                case 11: // Unrealized
                    e.Value = Round(expo.UnRealized);
                    e.ToolTip = string.Empty + expo.UnRealized;
                    break;

                case 12: // Fees
                    e.Value = Round(expo.FeesTracker.Fees);
                    e.ToolTip = string.Empty + expo.FeesTracker.Fees;
                    break;

                case 13: // PNL
                    e.Value = Round(expo.PL);
                    e.ToolTip = string.Empty + expo.PL;
                    break;

                case 14: // Net PNL
                    e.Value = Round(expo.NetPL);
                    e.ToolTip = string.Empty + expo.NetPL;
                    break;
            }
        }

        /// <summary>
        /// VirtualGridUIGridRowEnter
        /// </summary>
        /// <param name="sender">
        /// </param>
        /// <param name="e">
        /// </param>
        private void OnUniverseVirtualGridRowEnter(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
        {
            var codes = Singleton<Universe>.Instance.InstrumentViews;
            if (codes == null)
            {
                this.InstrumentView = null;
            }
            else
            {
                var code = codes[e.RowIndex];
                this.InstrumentView = Singleton<Universe>.Instance[code];
            }
        }

        /// <summary>
        /// The virtualGrid_ ui grid query row count.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnUniveseVirtualGridQueryRowCount(object sender, VirtualGridEventArgs.QueryRowCount e)
        {
            e.RowCount = Singleton<Universe>.Instance.InstrumentViews != null ? Singleton<Universe>.Instance.InstrumentViews.Length : 0;
        }

        /// <summary>
        /// The order tracking cells virtual grid_ row enter.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OrderTrackingCellsVirtualGrid_RowEnter(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
        {
            if (this.currentTrackingCells != null)
            {
                var cell = this.currentTrackingCells[e.RowIndex];
                if (cell != null)
                {
                    this.Executions = cell.Executions;
                    return;
                }
            }

            this.Executions = null;
        }

        /// <summary>
        /// The order tracking cells virtual grid ui grid query cell info.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OrderTrackingCellsVirtualGridUIGridQueryCellInfo(object sender, VirtualGridEventArgs.QueryCellInfo e)
        {
            if (e.RowIndex < 0)
            {
                return;
            }

            if (this.currentTrackingCells == null)
            {
                return;
            }

            var cell = this.currentTrackingCells[e.RowIndex];
            if (cell == null)
            {
                return;
            }

            switch (e.ColumnIndex)
            {
                case 0: // Time
                    e.Value = cell.AckStamp;
                    break;
                case 1: // Status
                    e.Value = cell.StringStatus;
                    break;
                case 2: // Type
                    e.Value = cell.Order.Type;
                    break;
                case 3: // way
                    e.Value = cell.Order.Way;
                    break;
                case 4: // requested qty
                    e.Value = cell.RequestedQuantity;
                    break;
                case 5: // requested price
                    e.Value = cell.RequestedPrice;
                    break;
                case 6: // remaining quantity
                    e.Value = cell.RemainingQuantity;
                    break;
                case 7: // average price
                    e.Value = cell.ExecAveragePrice;
                    break;
                case 8: // booking path
                    e.Value = cell.Order.BookingPath;
                    break;
            }
        }

        /// <summary>
        /// The order tracking cells virtual grid ui grid query row count.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OrderTrackingCellsVirtualGridUIGridQueryRowCount(object sender, VirtualGridEventArgs.QueryRowCount e)
        {
            e.RowCount = this.currentTrackingCells != null ? this.currentTrackingCells.Length : 0;
        }

        /// <summary>
        /// ResetUniverseExpoCell
        /// </summary>
        private void ResetUniverseExpoCell()
        {
            if (!this.built)
            {
                return;
            }

            if (Singleton<Universe>.Instance == null)
            {
                return;
            }

            if (this.TradingScopeCombobox == null)
            {
                return;
            }

            if (this.ExpositionTypeCombobox == null)
            {
                return;
            }

            var tradingScope = (ETradingScope)this.selectedTradingScope;
            var expoCellType = this.selectedExpoType;

            var expo = Singleton<Universe>.Instance[tradingScope];

            if (expo != null)
            {
                this.UniverseExpoCell = expo[expoCellType];
            }
        }

        /// <summary>
        /// The trading scope combobox selected index changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void TradingScopeComboboxSelectedIndexChanged(object sender, EventArgs e)
        {
            this.selectedTradingScope = (ETradingScope)this.TradingScopeCombobox.SelectedItem;

            this.uiInstrumentViewVirtualGrid.Rows.Clear();
            this.uiOrderTrackingCellsVirtualGrid.Rows.Clear();
            this.uiExecutionsVirtualGrid.Rows.Clear();

            this.Instrument = null;

            if (this.InstrumentView != null)
            {
                var predicate = PredicateBuilder.True<IInstrument>();
                predicate = predicate.And(cell => cell.InstrumentStaticData.TradingScope == this.selectedTradingScope);
                this.instruments = this.InstrumentView.GetInstruments(predicate).NestedObject;
            }

            this.ResetUniverseExpoCell();
        }

        /// <summary>
        /// The ui universe expo virtual grid_ ui grid query cell info.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void UIGridQueryCellInfo(object sender, VirtualGridEventArgs.QueryCellInfo e)
        {
            if (e.RowIndex < 0)
            {
                return;
            }

            // if (this.currentUniverseExpo == null)
            // {
            // return;
            // }
            switch (e.ColumnIndex)
            {
                case 0: // Scope
                    e.Value = this.selectedTradingScope;
                    break;
                case 1: // Type
                    e.Value = this.selectedExpoType;
                    break;
                case 2: // Currency
                    e.Value = "EUR";
                    break;
                case 3: // Long
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.NominalLong) : "-";
                    break;
                case 4: // Short
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.NominalShort) : "-";
                    break;
                case 5: // Expo
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.NominalExpo) : "-";
                    break;
                case 6: // Realized
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.Realized) : "-";
                    break;
                case 7: // UnRealized
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.UnRealized) : "-";
                    break;
                case 8: // Fees
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.Fees) : "-";
                    break;
                case 9: // PNL
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.PL) : "-";
                    break;
                case 10: // Net PNL
                    e.Value = this.UniverseExpoCell != null ? Round(this.UniverseExpoCell.NetPL) : "-";
                    break;
            }
        }

        /// <summary>
        /// The ui universe expo virtual grid_ ui grid query row count.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void UIGridQueryRowCount(object sender, VirtualGridEventArgs.QueryRowCount e)
        {
            e.RowCount = 1;
        }

        #endregion
    }
}